using System.Net;
using System.Net.Sockets;

namespace ApiLib.Utils;

/// <summary>
/// TCP帮助类
/// </summary>
public class TcpHelper
{
    private readonly int _localPort;
    private readonly string _remoteHost;
    private readonly int _remotePort;
    private TcpListener? _listener;
    private readonly Func<bool, byte[], byte[]>? _onListener;

    private TcpHelper(int localPort, string remoteHost = "", int remotePort = 0,
        Func<bool, byte[], byte[]>? onListener = null)
    {
        this._localPort = localPort;
        this._remoteHost = remoteHost;
        this._remotePort = remotePort;
        this._onListener = onListener;
    }

    /// <summary>
    /// 获取实例
    /// </summary>
    /// <param name="localPort">本地端口</param>
    /// <param name="onListener">监听</param>
    /// <returns></returns>
    public static TcpHelper GetInstance(int localPort, Func<bool, byte[], byte[]>? onListener = null)
    {
        return new TcpHelper(localPort, onListener: onListener);
    }

    /// <summary>
    /// 获取实例
    /// </summary>
    /// <param name="localPort">本地端口</param>
    /// <param name="remoteHost">远程地址</param>
    /// <param name="remotePort">远程端口</param>
    /// <param name="onListener">监听</param>
    /// <returns></returns>
    public static TcpHelper GetInstance(int localPort, string remoteHost, int remotePort,
        Func<bool, byte[], byte[]>? onListener = null)
    {
        return new TcpHelper(localPort, remoteHost, remotePort, onListener);
    }

    private static readonly SemaphoreSlim ClientSemaphore = new(100, 100); // 限制最大并发客户端数
    private static readonly CancellationTokenSource Cts = new();

    /// <summary>
    /// 停止监听
    /// </summary>
    public void StopListener()
    {
        _listener?.Stop();
    }

    /// <summary>
    /// 启动监听
    /// </summary>
    public async Task StartListener()
    {
        _listener = new TcpListener(IPAddress.Any, _localPort); // 选择一个不同的端口
        _listener.Start();
        Console.WriteLine("Listening for connections...");

        // Handle graceful shutdown
        Console.CancelKeyPress += (sender, eventArgs) =>
        {
            eventArgs.Cancel = true;
            Cts.Cancel();
        };

        while (!Cts.Token.IsCancellationRequested)
        {
            try
            {
                var client = await _listener.AcceptTcpClientAsync().ConfigureAwait(false);
                await ClientSemaphore.WaitAsync(Cts.Token).ConfigureAwait(false);

                // Start handling the client connection in a separate task
                _ = HandleClientAsync(client, Cts.Token).ContinueWith(task =>
                {
                    ClientSemaphore.Release(); // Ensure semaphore is released even if task fails
                }, TaskScheduler.Default);
            }
            catch (OperationCanceledException)
            {
                // Server is shutting down
                break;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error accepting client: {ex.Message}");
            }
        }

        _listener.Stop();
        Console.WriteLine("Server stopped.");
    }


    /// <summary>
    /// 处理客户端请求
    /// </summary>
    /// <param name="client"></param>
    /// <param name="cancellationToken"></param>
    private async Task HandleClientAsync(TcpClient client, CancellationToken cancellationToken)
    {
        using (client)
        using (var server = new TcpClient())
        {
            try
            {
                await server.ConnectAsync(_remoteHost, _remotePort, cancellationToken).ConfigureAwait(false);
                var clientStream = client.GetStream();
                var serverStream = server.GetStream();

                var forwardTask = ForwardDataAsync(clientStream, serverStream, true, cancellationToken);
                var reverseTask = ForwardDataAsync(serverStream, clientStream, false, cancellationToken);
                await Task.WhenAll(forwardTask, reverseTask).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
                // Connection was cancelled
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error handling client: {ex.Message}");
            }
        }
    }

    /// <summary>
    /// 请求转发
    /// </summary>
    /// <param name="source"></param>
    /// <param name="destination"></param>
    /// <param name="isClient">来自监听</param>
    /// <param name="cancellationToken"></param>
    private async Task ForwardDataAsync(NetworkStream source, NetworkStream destination, bool isClient,
        CancellationToken cancellationToken)
    {
        var direction = isClient ? "Client -> Server" : "Server -> Client";
        try
        {
            var buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead =
                       await source.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) > 0)
            {
                var bytes = buffer.Take(bytesRead).ToArray();
                Console.WriteLine($"{direction}: {BitConverter.ToString(bytes)}");
                var outBytes = _onListener?.Invoke(isClient, bytes) ?? bytes;
                await destination.WriteAsync(outBytes, cancellationToken).ConfigureAwait(false);
            }
        }
        catch (OperationCanceledException)
        {
            // Operation was cancelled
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error in {direction}: {ex.Message}");
        }
    }
}